


//  初始化着色器程序，让 WebGL 知道如何绘制我们的数据
function initShaderProgram(gl, vsSource, fsSource) {
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

  // 创建着色器程序

  const shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  // 如果创建失败，alert
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert(
      "Unable to initialize the shader program: " +
        gl.getProgramInfoLog(shaderProgram),
    );
    return null;
  }

  return shaderProgram;
}

//
// 创建指定类型的着色器，上传 source 源码并编译
//
function loadShader(gl, type, source) {
  const shader = gl.createShader(type);

  // Send the source to the shader object

  gl.shaderSource(shader, source);

  // Compile the shader program

  gl.compileShader(shader);

  // See if it compiled successfully

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    alert(
      "An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader),
    );
    gl.deleteShader(shader);
    return null;
  }

  return shader;
}







function main() {
	const canvas = document.querySelector("#glcanvas");

	const gl = canvas.getContext("webgl2");


	if (!gl) {
		alert("无法初始化 WebGL2，你的浏览器、操作系统或硬件等可能不支持 WebGL2。");
		return;
	}

	gl.viewport(0, 0, screen_width, screen_height);
	
	gl.clearColor(0.0, 0.0, 0.0, 1.0);

	gl.clear(gl.COLOR_BUFFER_BIT);
  //启用混合
	//gl.enable(gl.BLEND);
	//gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
	gl.enable(gl.DEPTH_TEST); // Enable depth testing
	gl.depthFunc(gl.LEQUAL); // Near things obscure far things
	
	//const default_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
	
	//使用拓展 帧缓冲数据类型支持
	//const ext = gl.getExtension("EXT_color_buffer_float");
  
	//用于HDR的帧缓冲
	//let FBO_hdr = gl.createFramebuffer();
	//let tex_hdr = gl.createTexture();
	//纹理
	//gl.bindTexture(gl.TEXTURE_2D, tex_hdr);
	//gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, screen_width, screen_height, 0, gl.RGBA, gl.FLOAT, null);//*********************
	//gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
	//gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
	//深度缓冲
	//let dep_hdr = gl.createRenderbuffer();
	//gl.bindRenderbuffer(gl.RENDERBUFFER, dep_hdr);
	//gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, screen_width, screen_height);
	
	//gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr);
	/*
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_hdr, 0);
	gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, dep_hdr);
	if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE){
		alert("Framebuffer not complete!");
	}
	gl.bindFramebuffer(gl.FRAMEBUFFER, default_framebuffer);*/
	
	const default_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);

	//使用拓展
	const ext = gl.getExtension("EXT_color_buffer_float");


	//用于HDR的帧缓冲
	let FBO_hdr_full_size = gl.createFramebuffer();
	let tex_hdr_full_size = gl.createTexture();
	//纹理
	gl.bindTexture(gl.TEXTURE_2D, tex_hdr_full_size);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, screen_width, screen_height, 0, gl.RGBA, gl.FLOAT, null);//*********************
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	//深度缓冲
	let dep_hdr_full_size = gl.createRenderbuffer();
	gl.bindRenderbuffer(gl.RENDERBUFFER, dep_hdr_full_size);
	gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, screen_width, screen_height);

	gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr_full_size);
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_hdr_full_size, 0);
	gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, dep_hdr_full_size);
	if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
		alert("Framebuffer not complete!");
	}


	const num_framebuffer = 2;

	let FBO_hdr = [];
	let tex_hdr = [];
	// let array_span_pixel = [];
	// let array_buffer_size = [];

	let buffer_width = screen_width ;
	let buffer_height = screen_height ;
	for (let i = 0; i < num_framebuffer; i += 1) {
		//用于计算边界的帧缓冲

		let framebuffer_tmp = gen_framebuffer(gl, buffer_width, buffer_height);

		FBO_hdr[i] = framebuffer_tmp[0];
		tex_hdr[i] = framebuffer_tmp[1];
	}


	let buffer_jewel = gen_framebuffer(gl, screen_width, screen_height);
  
	
	
	//编译链接着色器
	const shaderProgram_jewel = initShaderProgram(gl, vertex_jewel_source, fragment_jewel_source);
	const shaderProgram_rect = initShaderProgram(gl, vertex_rect_source, fragment_rect_source);
	const shaderProgram_after0 = initShaderProgram(gl, vertex_after0_source, fragment_after0_source);
	const shaderProgram_blend = initShaderProgram(gl, vertex_rect_source, fragment_blend_source);


	//顶点属性
	const programInfo_jewel = {
		program: shaderProgram_jewel,
		attribLocations: {
			vertexPosition: gl.getAttribLocation(shaderProgram_jewel, "aPos"),
			normPosition: gl.getAttribLocation(shaderProgram_jewel, "norm"),
		},
		uniformLocations: {
			one_Matrix: gl.getUniformLocation(shaderProgram_jewel, "one_matrix"),
			rotate_xz: gl.getUniformLocation(shaderProgram_jewel, "rotate_xz"),
			view_position: gl.getUniformLocation(shaderProgram_jewel, "view_position"),
			seed: gl.getUniformLocation(shaderProgram_jewel, "seed"),
			line: gl.getUniformLocation(shaderProgram_jewel, "line"),
		},
	};


	const programInfo_rect = {
		program: shaderProgram_rect,
		attribLocations: {
			vertexPosition: gl.getAttribLocation(shaderProgram_rect, "aPos_n_texcoord"),
		},
		uniformLocations: {
			Tex_hdr: gl.getUniformLocation(shaderProgram_rect, "Tex_hdr"),
			pixel_span: gl.getUniformLocation(shaderProgram_rect, "pixel_span"),

		},
	};


	const programInfo_after0 = {
		program: shaderProgram_after0,
		attribLocations: {
			
		},
		uniformLocations: {
			one_Matrix: gl.getUniformLocation(shaderProgram_after0, "one_matrix"),
			rotate_xz: gl.getUniformLocation(shaderProgram_after0, "rotate_xz"),
		},
	};

	const programInfo_blend = {
		program: shaderProgram_blend,
		attribLocations: {
			
		},
		uniformLocations: {
			line: gl.getUniformLocation(shaderProgram_blend, "line"),
			jewel: gl.getUniformLocation(shaderProgram_blend, "jewel"),
		},
	};
	
	
	//顶点数组设置

	const VAO_jewel = jewel_vao_gen(gl, programInfo_jewel);
	const VAO_rect = VAO_rect_generate(gl, programInfo_rect);
	
	//纹理绑定
	gl.activeTexture(gl.TEXTURE0);
	gl.bindTexture(gl.TEXTURE_2D, tex_hdr[0]);

	gl.activeTexture(gl.TEXTURE1);
	gl.bindTexture(gl.TEXTURE_2D, tex_hdr[1]);

	gl.activeTexture(gl.TEXTURE2);
	gl.bindTexture(gl.TEXTURE_2D, buffer_jewel[1]);
			
	function render(now) {

		
		
		
		//按键控制
		if(w_down == 1)
			position_move(move_speed, 0, angle_xz);
		if(s_down == 1)
			position_move(-move_speed, 0, angle_xz);
		if(a_down == 1)
			position_move(0, move_speed, angle_xz);
		if(d_down == 1)
			position_move(0, -move_speed, angle_xz);
		if(q_down == 1)
			move_y += move_speed;
		if(e_down == 1){
			move_y -= move_speed;
			
		}
		

		
		
		
		const perspec = [
		1.0, 0.0, 0.0, 0.0, 0.0, screen_width/screen_height, 0.0, 0.0, 0.0, 0.0, -1.001, -1.0, 0.0, 0.0, -0.21, 0.0];
		
					
		
		//const rotate_cube = quad2matrix(0.707, 0 ,0.707, 0);//test
		
		const xz_sin = Math.sin(angle_xz);
		const xz_cos = Math.cos(angle_xz);
		const y_sin = Math.sin(angle_y);
		const y_cos = Math.cos(angle_y);

		const rotate = rotate_matrix(xz_sin, xz_cos, y_sin, y_cos);//旋转矩阵

		const angle_value = parseFloat(angle_range.value);
		const rotate_xz = rotate_matrix_xz(Math.sin(angle_value), Math.cos(angle_value));
		
		//镜头透视 旋转 位移矩阵
		const cam_matrix = cam_matrix_gen([- move_x, - move_y, - move_z], rotate, perspec);


		
		//法线图
		gl.viewport(0, 0, buffer_width, buffer_height);
		gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr[0]);
		gl.clearColor(0.0, 0.0, 0.0, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		gl.bindVertexArray(VAO_jewel);
		gl.useProgram(shaderProgram_after0);
		gl.uniformMatrix4fv(
			programInfo_after0.uniformLocations.one_Matrix,
			false,
			new Float32Array(cam_matrix),
		);
		gl.uniformMatrix4fv(
			programInfo_after0.uniformLocations.rotate_xz,
			false,
			new Float32Array(rotate_xz),
		);
		gl.drawArrays(gl.TRIANGLES, 0, 3 * 20);

		//卷积核 后处理
		gl.viewport(0, 0, buffer_width, buffer_height);
		gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr[1]);
		gl.clearColor(0.0, 0.0, 0.0, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		gl.bindVertexArray(VAO_rect);
		gl.useProgram(programInfo_rect.program);
		gl.uniform2f(programInfo_rect.uniformLocations.pixel_span, 
			1.0 / buffer_width, 
			1.0 / buffer_height
		);
		gl.uniform1i(programInfo_rect.uniformLocations.Tex_hdr, 0);
		
		gl.drawElements(gl.TRIANGLES, 6 , gl.UNSIGNED_SHORT, 0);

		

		//jewel图像
		gl.viewport(0, 0, screen_width, screen_height);
		gl.bindFramebuffer(gl.FRAMEBUFFER, buffer_jewel[0]);
		gl.clearColor(0.1, 0.1, 0.1, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		//渲染
		gl.bindVertexArray(VAO_jewel);
		gl.useProgram(programInfo_jewel.program);
		gl.uniformMatrix4fv(
			programInfo_jewel.uniformLocations.one_Matrix,
			false,
			new Float32Array(cam_matrix),
		);
		gl.uniformMatrix4fv(
			programInfo_jewel.uniformLocations.rotate_xz,
			false,
			new Float32Array(rotate_xz),
		);
		gl.uniform3f(
			programInfo_jewel.uniformLocations.view_position,
			move_x,
			move_y,
			move_z
		);
		gl.uniform1f(
			programInfo_jewel.uniformLocations.seed,
			10.35675849 + angle_value / 500.0
		);	
		//gl.drawElements(gl.TRIANGLES, 6 * (num_cycle + num_cycle - 2) , gl.UNSIGNED_SHORT, 0);
		gl.drawArrays(gl.TRIANGLES, 0, 3 * 20);


		//最终混合图像
		gl.viewport(0, 0, screen_width, screen_height);
		gl.bindFramebuffer(gl.FRAMEBUFFER, default_framebuffer);
		gl.clearColor(0.1, 0.1, 0.1, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		gl.bindVertexArray(VAO_rect);
		gl.useProgram(programInfo_blend.program);
		gl.uniform1i(programInfo_blend.uniformLocations.line, 1);
		gl.uniform1i(programInfo_blend.uniformLocations.jewel, 2);
		gl.drawElements(gl.TRIANGLES, 6 , gl.UNSIGNED_SHORT, 0);


		requestAnimationFrame(render);
	}
	
	requestAnimationFrame(render);
}




let angle_xz = 0;
let angle_y = 0;
let x = 0;
let y = 0;
let isclick = false;

const move_speed = 0.05;
let move_x = 0;
let move_z = 2.5;
let move_y = 0.0;


//const screen_width = 640;
//const screen_height = 480;
//鼠标事件
function handle_mousemove(event){
	const x_current = event.offsetX;
	const y_current = event.offsetY;
	
	if(isclick){
		angle_xz +=  (x_current - x) / screen_width * Math.PI / 2.0;
		angle_y += (y_current - y) / screen_height * Math.PI / 2.0;
		//限位
		if(angle_y > Math.PI / 2.0){
			angle_y = Math.PI / 2.0;
		}else if(angle_y < -Math.PI / 2.0){
			angle_y = -Math.PI / 2.0;
		}
	}
	
	x = x_current;
	y = y_current;
}

function handle_mousedown(event){
	isclick = true;
}

function handle_mouseup(event){
	isclick = false;
}

function position_move(fr_ba, le_ri, angle){
	//前后运动
	move_z -= Math.cos(angle) * fr_ba;
	move_x -= Math.sin(angle) * fr_ba;
	
	//左右运动
	move_z -= -Math.sin(angle) * le_ri;
	move_x -= Math.cos(angle) * le_ri;
}


let w_down = 0;
let s_down = 0;
let a_down = 0;
let d_down = 0;
let q_down = 0;
let e_down = 0;

function handle_keydown(event){
	switch(event.code){
		case "KeyW":
		w_down = 1;
		//position_move(move_speed, 0, angle_xz);
		
		break;
		case "KeyS":
		s_down = 1;
		//position_move(-move_speed, 0, angle_xz);
		break;
		case "KeyA":
		a_down = 1;
		//position_move(0, move_speed, angle_xz);
		break;
		case "KeyD":
		d_down = 1;
		//position_move(0, -move_speed, angle_xz);
		break;
		//增加上升和下降
		case "KeyQ":
		q_down = 1;
		//position_move(0, -move_speed, angle_xz);
		break;
		case "KeyE":
		e_down = 1;
		//position_move(0, -move_speed, angle_xz);
		break;
		
	}
}

function handle_keyup(event){
	switch(event.code){
		case "KeyW":
		w_down = 0;
		
		break;
		case "KeyS":
		s_down = 0;
		break;
		case "KeyA":
		a_down = 0;
		break;
		case "KeyD":
		d_down = 0;
		break;
		//
		case "KeyQ":
		q_down = 0;
		break;
		case "KeyE":
		e_down = 0;
		break;
		
	}
}

//像素大小初始化
let screen_width = window.innerWidth;
document.querySelector("#glcanvas").width = screen_width;

let screen_height = window.innerHeight;
document.querySelector("#glcanvas").height = screen_height;

//事件监听
const angle_range = document.querySelector("#angle");

document.querySelector("#glcanvas").addEventListener("mousemove", handle_mousemove);
document.querySelector("#glcanvas").addEventListener("mousedown", handle_mousedown);
document.querySelector("#glcanvas").addEventListener("mouseup", handle_mouseup);
window.addEventListener("keydown", handle_keydown);
window.addEventListener("keyup", handle_keyup);

document.addEventListener("DOMContentLoaded", main);